﻿using GrayParrot.Core.Data;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace GrayParrot.Data.EntityFramework
{
    public class Repository<T, Tkey> : IRepository<T, Tkey>, IDisposable where T : class where Tkey : class
    //where Context : DbContext, new ()
    {
        DbContext _entity = null;

        public Repository(DbContext context)
        {
            _entity = context;
        }

        public void Add(T entity)
        {
            _entity.Set<T>().Add(entity);
            _entity.Entry(entity).State = System.Data.Entity.EntityState.Added;
        }

        public void Remove(T entity)
        {
            _entity.Set<T>().Remove(entity);
            _entity.Entry(entity).State = System.Data.Entity.EntityState.Deleted;
        }

        public void Remove(Tkey key)
        {
            T entity = Find(key);
            Remove(entity);
        }

        public void Update(T entity)
        {
            _entity.Entry(entity).State = System.Data.Entity.EntityState.Modified;
        }

        public IQueryable<T> FindAll()
        {
            return _entity.Set<T>();
        }

        public IQueryable<T> FindAll(
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> Query = _entity.Set<T>();

            if (!string.IsNullOrEmpty(includeProperties))
            {
                foreach (string IncludeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    Query = Query.Include(IncludeProperty);
                }
            }

            if (orderBy != null)
            {
                return orderBy(Query);
            }
            return Query;
        }

        public T Find(Tkey i)
        {
            PropertyInfo[] m_props = i.GetType().GetProperties();
            object[] m_keys = new object[m_props.Count()];
            for(int n=0; n<=m_props.Count()-1; n++)
            {
                m_keys.SetValue(m_props[n].GetValue(i, null), n);
            }

            return _entity.Set<T>().Find(m_keys);
        }

        public virtual IQueryable<T> Find(
            Expression<Func<T, bool>> filter = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> Query = _entity.Set<T>();

            if (filter != null)
            {
                Query = Query.Where(filter);
            }

            if (!string.IsNullOrEmpty(includeProperties))
            {
                foreach (string IncludeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    Query = Query.Include(IncludeProperty);
                }
            }

            if (orderBy != null)
            {
                return orderBy(Query);
            }
            return Query;
        }

        //public void Save()
        //{
        //    try
        //    {
        //        _entity.SaveChanges();
        //    }
        //    catch (DbEntityValidationException ex)
        //    {
        //        // Retrieve the error messages as a list of strings.
        //        var errorMessages = ex.EntityValidationErrors
        //                .SelectMany(x => x.ValidationErrors)
        //                .Select(x => x.ErrorMessage);

        //        // Join the list to a single string.
        //        var fullErrorMessage = string.Join("; ", errorMessages);

        //        // Combine the original exception message with the new one.
        //        var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

        //        GrayParrot.Logging.Logger.For<T>().Error(exceptionMessage, ex);

        //        // Throw a new DbEntityValidationException with the improved exception message.
        //        throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        //    }
        //    catch (Exception ex)
        //    {
        //        GrayParrot.Logging.Logger.For<T>().Error("Errore in Save", ex);
        //    }
        //}

        public void Dispose()
        {
            if (_entity != null)
            {
                _entity.Dispose();
            }
        }



        [Obsolete("Not Use this method", true)]
        public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
        {
            throw new NotImplementedException();
        }

        [Obsolete("Not Use this method", true)]
        IEnumerable<T> IRepository<T, Tkey>.FindAll()
        {
            throw new NotImplementedException();
        }
    }
}
